package ufo.server

import _root_.scala.collection.mutable.{HashMap, MutableList}
import api.action._
import api.common.{Position, Direction}
import api.event._
import api.{ActionPerformer, EventListener}
import domain.BeingContainer
import java.util.UUID

class World(width : Int, height : Int) extends EventListener with BeingContainer[ServerBeing] {
  implicit val world = this
  var clients : List[Client] = Nil
  var turn : Turn = null

  override def add(being : ServerBeing) = {
    super.add(being)
	  notify(new BeingSpotted(being.id, being.position, being.controlledBy.id, being.hitPoints))
  }

  def validate(pos : Position) = {
    if (pos.x < 0 || pos.y < 0 || pos.x >= width || pos.y >= height) {
      throw IllegalActionException("Outside world")
    }
  }

  def addClient(client : Client) = {
    clients = client :: clients
	  client.notify(new Initialize(width, height, client.id)) 
  }

  def notify(event : Event) = {
    clients.foreach(x => x.notify(event))
  }

  def newTurn() = {
    if (clients.isEmpty) {
      throw new IllegalStateException("No clients connected")
    }
    turn = new Turn(clients)
    turn.nextClient()
  }

  def endTurn(client : Client) = {
    turn.nextClient()
  }

  def damage(position : Position, hp : Int) = {
    findBeingAt(position).foreach(_.injure(hp))
  }
}

class Turn(clients : List[Client])(implicit world : World) {
  var remainingClients : List[Client] = clients
  var currentClient : Client = null

  def nextClient() : Unit = {
    remainingClients match {
      case next :: tail =>
        remainingClients = tail
        currentClient = next
        world.beings.values.filter(b => b.controlledBy == currentClient).foreach(b => b.beginTurn())
        world.notify(BeginTurn(currentClient.id))
      case List() =>
        world.newTurn()
    }
  }
}

case class IllegalActionException(reason : String) extends RuntimeException

class Team {

}

trait DelegatingEventListener extends EventListener {
  def eventListener() : EventListener

  def notify(event : Event) = {
    eventListener().notify(event)
  }
}

class Client(val id : UUID, val eventListener : EventListener)(implicit world : World) extends ActionPerformer with DelegatingEventListener {
  def perform(action : Action) = {
    try {
      if (world.turn.currentClient != this) {
        throw new IllegalActionException("It is not your turn")
      }
      if (action.isInstanceOf[BeingAction]) {
        val beingAction = action.asInstanceOf[BeingAction]
        val being = world.getBeing(beingAction.beingId)
        if (being.isDefined && being.get.controlledBy == this) {
          being.get.perform(beingAction)
        } else {
          throw IllegalActionException("You cannot control this being")
        }
      } else {
        action match {
          case EndTurn() => world.endTurn(this)
        }
      }
    } catch {
      case IllegalActionException(reason) =>
        eventListener.notify(IllegalAction(action, reason))
    }
  }

}



trait Weapon {
  def fire(target : Position)
}

class Rifle(implicit world : World) extends Weapon {
  def fire(target : Position) = {
    world.damage(target, (5*Math.random).toInt)
  }

}